;  PROGRAM:  MENU
;  AUTHOR:  RICHARD CONN
;  VERSION:  1.4
;  DATE:  16 Jan 83
;  PREVIOUS VERSIONS:  1.3 (9 Jan 83)
;  PREVIOUS VERSIONS:  1.2 (6 Jan 83), 1.1 (13 Dec 82), 1.0 (11 DEC 82)
;
VERS	EQU	14

;****************************************************************
;*		07/05/83 converted to 8080 code			*
;*			by HM Van Tassell			*
;*			201/755-5372				*
;****************************************************************
;	This program is Copyright (c) 1982, 1983 by Richard Conn
;	All Rights Reserved
;
;	ZCPR2 and its utilities, including this one, are released
; to the public domain.  Anyone who wishes to USE them may do so with
; no strings attached.  The author assumes no responsibility or
; liability for the use of ZCPR2 and its utilities.
;
;	The author, Richard Conn, has sole rights to this program.
; ZCPR2 and its utilities may not be sold without the express,
; written permission of the author.
;


;
;	MENU is the ZCPR2 Menu Processor.  It loads, looks for the MENU.CPR
; file, and then displays it to the user (optionally) and prompts him for
; a single-character command.  The ZCPR2 Multiple Command Line Buffer must
; be installed for MENU to work, and MENU uses this buffer to chain to the
; programs selected by the user and return to itself at the proper place.
;
;	MENU supports multiple menus within one MENU.CPR file.  When a command
; is invoked, MENU returns to the menu the command came from.
;
;	MENU will ONLY RUN on ZCPR2 systems with the Multiple Command Line
; Buffer Option enabled.
;

;
;  Menu Constants
;

;  1 Special Menu Command Chars
RNM		EQU	'>'		;NEXT MENU
RNMP		EQU	'.'		;NEXT MENU PRIME (ALTERNATE)
RLM		EQU	'<'		;LAST MENU
RLMP		EQU	','		;LAST MENU PRIME (ALTERNATE)
RFM		EQU	'*'		;FIRST MENU
RSM		EQU	'$'		;SYSTEM MENU (PASSWORD REQUIRED)
					; THIS IS SAME AS CONTROL CHAR
;  2 Internal Menu Control Chars
MCMD		EQU	':'		;COMMAND TO JUMP TO ANOTHER MENU
PCHAR		EQU	'"'		;INDICATES AUTO PROMPT FOR SPECIFIC CMD
MINDIC		EQU	'#'		;MENU SECTION INDICATOR
MFIRST		EQU	'%'		;FIRST MENU INDICATOR
GOPTION		EQU	'-'		;GLOBAL OPTION INDICATOR
WOPTION		EQU	'!'		;ACTIVATES WAIT UPON RETURN
WAITCH		EQU	'W'		;CHAR IN COMMAND LINE TO CAUSE WAIT

;  3 Menu Option Chars
COPTION		EQU	'C'		;DISPLAY COMMAND LINE TO USER
DOPTION		EQU	'D'		;DISPLAY MENU TO USER
POPTION		EQU	'P'		;PAGE OUT MENU DISPLAY TO USER
XOPTION		EQU	'X'		;DISABLE CP/M RETURN

;  4 Miscellaneous
CMDSEP		EQU	';'		;ZCPR2 COMMAND SEPARATOR
NLINES		EQU	24		;NUMBER OF LINES ON USER'S CRT

;
;  CP/M CONSTANTS
;
wboot	equ	0
bentry	equ	5
fcb	equ	5ch
tbuff	equ	80h
CR	equ	0dh
LF	equ	0ah
CTRLC	equ	'C'-'@'
TAB	equ	'I'-'@'
CTRLZ	equ	'Z'-'@'

;
;  Externals from SYSLIB
;
	ext	print
	ext	cin
	ext	cout
	ext	caps
	ext	crlf
	ext	madc
	ext	bline
	ext	initfc
	ext	f$open
	ext	f$clos
	ext	f$read
	ext	codend
	ext	hmovb
;
;  Branch to Start of Program
;
	.z80			;Zilog Z80 Mnemonics
	jp	start

;
;******************************************************************
;
;  SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format
;
;	This data block precisely defines the data format for
; initial features of a ZCPR2 system which are required for proper
; initialization of the ZCPR2-Specific Routines in SYSLIB.
;

;
;  EXTERNAL PATH DATA
;
EPAVAIL:
	DB	0FFH	; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES)
EPADR:
	DW	40H	; ADDRESS OF EXTERNAL PATH IF AVAILABLE

;
;  INTERNAL PATH DATA
;
INTPATH:
	DB	0,0	; DISK, USER FOR FIRST PATH ELEMENT
			; DISK = 1 FOR A, '$' FOR CURRENT
			; USER = NUMBER, '$' FOR CURRENT
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0	; DISK, USER FOR 8TH PATH ELEMENT
	DB	0	; END OF PATH

;
;  MULTIPLE COMMAND LINE BUFFER DATA
;
MCAVAIL:
	DB	0FFH	; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE?
MCADR:
	DW	0FF00H	; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE

;
;  DISK/USER LIMITS
;
MDISK:
	DB	4 	; MAXIMUM NUMBER OF DISKS
MUSER:
	DB	31	; MAXIMUM USER NUMBER

;
;  FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK
;
DOK:
	DB	0FFH	; ALLOW DISK CHANGE? (0=NO, 0FFH=YES)
UOK:
	DB	0FFH	; ALLOW USER CHANGE? (0=NO, 0FFH=YES)

;
;  PRIVILEGED USER DATA
;
PUSER:
	DB	10	; BEGINNING OF PRIVILEGED USER AREAS
PPASS:
	DB	'chdir',0	; PASSWORD FOR MOVING INTO PRIV USER AREAS
	DS	41-($-PPASS)	; 40 CHARS MAX IN BUFFER + 1 for ending NULL

;
;  CURRENT USER/DISK INDICATOR
;
CINDIC:
	DB	'$'	; USUAL VALUE (FOR PATH EXPRESSIONS)

;
;  DMA ADDRESS FOR DISK TRANSFERS
;
DMADR:
	DW	80H	; TBUFF AREA

;
;  NAMED DIRECTORY INFORMATION
;
NDRADR:
	DW	0FD00H	; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY
NDNAMES:
	DB	50	; MAX NUMBER OF DIRECTORY NAMES
DNFILE:
	DB	'NAMES   '	; NAME OF DISK NAME FILE
	DB	'DIR'		; TYPE OF DISK NAME FILE

;
;  REQUIREMENTS FLAGS
;
EPREQD:
	DB	000H	; EXTERNAL PATH?
MCREQD:
	DB	0FFH	; MULTIPLE COMMAND LINE?
MXREQD:
	DB	000H	; MAX USER/DISK?
UDREQD:
	DB	000H	; ALLOW USER/DISK CHANGE?
PUREQD:
	DB	0FFH	; PRIVILEGED USER?
CDREQD:
	DB	000H	; CURRENT INDIC AND DMA?
NDREQD:
	DB	000H	; NAMED DIRECTORIES?
Z2CLASS:
	DB	0	; CLASS 0
	DB	'ZCPR2'
	DS	10	; RESERVED

;
;  END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;

;
;  This is the FCB which defines the default name of the MENU.CPR file
;
menufcb:
	db	0		;FCB for MENU.CPR
	db	'MENU    '
	db	'CPR'
	ds	4
scratch:			;this doubles as a scratch area
	ds	16		;buffer definition is at end of program
	ds	4		;36 bytes total

;
;  Start of Program
;
start:
	call	print
	db	'MENU  Version '
	db	(vers/10)+'0','.',(vers mod 10)+'0',0

	ld	a,(mcavail)	;multiple command lines must be available
	or	a		;0=no
	jp	nz,start0
	call	print
	db	' - MC',0
	ret
start0:
	ld	hl,fcb+1	;check for menu number
	ld	a,(hl)		;check first char for delay
	cp	WAITCH		;wait?
	jp	nz,start1	;go ahead with number if no wait
	call	sak		;Strike Any Key
	inc	hl		;pt to char after W
start1:
	call	eval		;extract number (will return 0 if none there)
	ld	(reentry),a

	call	crlf		;new line
	ld	de,menufcb	;pt to MENU.CPR FCB
	call	initfc		;init fcb
	call	f$open		;open file
	ret	nz		;abort if no menu

;
;  Load MENU.CPR from disk
;
	call	codend		;get address of buffer for menu load
	ld	(mladr),hl	;set menu load address ptr

mload:
	ld	de,menufcb	;pt to FCB
	call	f$read		;read in next block
	or	a		;error?
	jp	nz,mloaddn	;load done if error
	ld	de,tbuff	;copy from TBUFF into memory pted to by HL
	ex	de,hl		;HL is source, DE is dest
	ld	b,128		;128 bytes
	call	hmovb
	ld	hl,(bentry+1)	;get address of top of TPA
	ld	a,h		;set to bottom of ZCPR2
	sub	10
	cp	d		;about to overflow ZCPR2?
	jp	nc,mload1	;continue if not
	call	print
	db	cr,lf,'Full',0
	ret
mload1:
	ex	de,hl		;HL pts to next byte to load to
	jp	mload		;continue load


;
;  Init Flags and Clear MSB of all bytes in Menu File
;
mloaddn:
	call	f$clos		;close input file
	ld	(hl),CTRLZ	;ensure EOF mark
	xor	a		;A=0
	ld	(cflag),a	;turn off command display
	ld	(dflag),a	;turn off menu display
	ld	(pflag),a	;disallow paging
	ld	(cpmok),a	;turn off CP/M return flag
	ld	(menuno),a	;set menu number to start at
	ld	hl,(mladr)	;pt to beginning of file
	push	hl		;save ptr
menul1:
	ld	a,(hl)		;get byte
	and	7FH		;mask out MSB
	ld	(hl),a		;put byte
	inc	hl		;pt to next
	cp	CTRLZ		;EOF?
	jp	nz,menul1	;continue if not
;
;  Mark all Menu Sections
;
	pop	hl		;HL pts to first byte of menu
	ld	b,0FFH		;set menu counter
;
;  Skip to Next Menu
;
menul2:
	ld	a,(hl)		;get byte
	cp	CTRLZ		;error?
	jp	z,mstrerr	;structure error if so
	cp	MINDIC		;menu indicator (start of menu?)
	jp	nz,menul4
	or	80H		;beginning of menu found -- set MSB
	ld	(hl),a		;put byte
	inc	b		;increment menu count
	inc	hl		;pt to next
	ld	a,(hl)		;get byte
	cp	MINDIC		;menu indicator (end of menu?)
	jp	z,menul5	;done if so
	cp	CTRLZ		;error?
	jp	z,mstrerr
	cp	RSM		;system menu indicator?
	jp	nz,menul3
	ld	a,b		;set system menu number
	ld	(smeno),a
	ld	a,0FFH		;set flag
	ld	(smenfl),a	;system menu present
	dec	hl		;back up to beginning of menu
	ld	(smenadr),hl	;start address
	inc	hl		;pt to RSM
;
;  Skip out Menu Display
;
menul3:
	call	lskipt		;skip to beginning of next line
	jp	z,menul4	;found menu indicator
	cp	CTRLZ		;error?
	jp	z,mstrerr
	jp	menul3		;continue if not
;
;  Skip to Next Menu
;
menul4:
	call	lskip		;skip to beginning of next menu
	jp	menul2
;
;  Check Menu Options
;
menul5:
	ld	hl,(mladr)	;pt to beginning of file
	ld	a,(hl)		;check for option
	cp	goption		;global option char?
	jp	nz,mfile	;if no global option, scan for menu files
	inc	hl		;pt to option char
option:
	ld	a,(hl)		;get option char
	call	caps		;capitalize
	inc	hl		;pt to next
	cp	cr		;done?
	jp	z,optdn
	cp	COPTION		;display command?
	jp	z,optc
	cp	DOPTION		;display menu?
	jp	z,optd
	cp	POPTION		;paging?
	jp	z,optp
	cp	XOPTION		;exit OK?
	jp	nz,mstrerr	;option error if not
;
;  Disable Exit to CP/M
;
	ld	a,0FFH		;turn flag off
	ld	(cpmok),a
	jp	option
;
;  Process Paging Option
;
optp:
	ld	a,0FFH		;set flag
	ld	(pflag),a
	jp	option
;
;  Process Display Menu Option
;
optd:
	ld	a,0FFH		;set flag
	ld	(dflag),a
	jp	option
;
;  Process Display Command Option
;
optc:
	ld	a,0FFH		;set flag
	ld	(cflag),a
	jp	option

;
;  Option Processing Done
;
optdn:
	inc	hl		;skip LF

;
;  Check for Menu Display
;
mfile:
	ld	a,(hl)		;get first byte
	and	7FH		;mask
	cp	MINDIC		;start of menu?
	jp	nz,mstrerr

;
;  Check and Set First Menu
;
	ld	(mstart),hl	;save start address of first menu item
	ld	(hl),mfirst+80H	;set first char of first menu

;
;  Entry Point for Menu Display
;	On entry, HL pts to first byte of current menu
;
dmenu:
	ld	a,(reentry)	;get reentry flag
	or	a		;0=no
	jp	nz,mchc0	;skip to proper menu
	ld	(cstart),hl	;save start address of current menu
	ld	a,(cflag)	;copy display command flag for temp use
	ld	(cpflag),a
	ld	a,(dflag)	;copy display menu flag for temp use
	ld	(dpflag),a
	ld	a,(pflag)	;copy paging flag for temp use
	ld	(ppflag),a
	inc	hl		;pt to first char after menu indicator char
dispm1:
	ld	a,(hl)		;get char
	call	caps		;capitalize
	inc	hl		;pt to next
	cp	cr		;end of options?
	jp	z,dispm2
	cp	RSM		;system menu?
	jp	z,dispm1	;ok if so
	cp	COPTION		;command display?
	jp	z,dispmc
	cp	DOPTION		;display?
	jp	z,dispmd
	cp	POPTION		;paging?
	jp	z,dispmp
	cp	XOPTION		;CP/M return?
	jp	nz,mstrerr	;error if not
;
;  Toggle CP/M Return Option
;
	ld	a,(cpmok)	;get flag
	cpl			;toggle
	ld	(cpmok),a
	jp	dispm1
;
;  Toggle Paging Option
;
dispmp:
	ld	a,(ppflag)	;get flag
	cpl			;toggle
	ld	(ppflag),a
	jp	dispm1
;
;  Toggle Display Menu Option
;
dispmd:
	ld	a,(dpflag)	;get flag
	cpl			;toggle
	ld	(dpflag),a
	jp	dispm1
;
;  Toggle Display Command Option
;
dispmc:
	ld	a,(cpflag)	;get flag
	cpl			;toggle
	ld	(cpflag),a
	jp	dispm1
;
;  Done with Menu-Specific Option Processing
;
dispm2:
	call	lskip		;skip to LF
	ld	a,(dpflag)	;display menu?
	or	a		;0=no
	jp	z,dispm8	;skip over menu if not
	ld	a,NLINES-1	;number of lines
	ld	(pagcnt),a	;set count
	call	crlf		;new line
;
;  Print Next Line of Menu if not Starting with ESCAPE Char (MINDIC)
;
dispm3:
	ld	a,(hl)		;get first char of line
	and	7FH		;mask
	cp	MINDIC		;done?
	jp	z,dispm4
	call	lprintx		;print line pted to by HL ending in <CR>
	jp	dispm3
;
;  Done with Menu Display -- Page it out
;
dispm4:
	call	lskip		;skip to first char of next line (option char)
	ld	(optstrt),hl	;set start address of options
	ld	a,(pagcnt)	;number of remaining lines
	ld	b,a		;count in B
	or	a		;ok?
	jp	z,dispm6	;don't do anything if already there
	ld	a,(ppflag)	;page?
	or	a		;0=No
	jp	z,dispm6
;
;  Page Loop for Menu Display
;
dispm5:
	call	crlf		;new line
	DEC	B		;@@
	JP	NZ,DISPM5
;	djnz	dispm5
;
;  Determine if Another Menu Follows
;
dispm6:
	xor	a		;A=0
	ld	(nmenfl),a	;set for no next menu
	ld	a,(hl)		;ok?
	and	7FH		;mask
	cp	CTRLZ		;error if EOF
	jp	z,mstrerr
	cp	MINDIC		;next menu?
	jp	nz,dispm7
	inc	hl		;double indicator if end
	ld	a,(hl)
	cp	MINDIC		;end?
	jp	z,dispm9
	cp	RSM		;system menu = no next menu
	jp	z,dispm9
	ld	a,0FFH		;set next menu
	ld	(nmenfl),a
	jp	dispm9
dispm7:
	call	lskip		;skip to next line
	jp	dispm6

;
;  Skip over current menu so it is not displayed
;
dispm8:
	call	lskipt		;skip to beginning of command
	jp	nz,dispm8
	call	lskip		;skip over end of display indicator
	ld	(optstrt),hl	;set pointer to options
	jp	dispm6		;determine if next menu available
dispm9:

;
;  Ready for Option Input
;    The following Flags/Values are now set:
;	CPFLAG -- Display Command Flag (0=No, 0FFH=Yes)
;	DPFLAG -- Display Menu Flag (0=No, 0FFH=Yes)
;	OPTSTRT -- Address of First Menu Option
;	NMENFL -- 0 if no next menu, 0FFH if next menu
;	MSTART -- Start Address of MINDIC Before Menu Display
;	  (MSTART)=MFIRST with MSB Set
prompt:
	ld	a,0ffh
	ld	(pagcnt),a	;turn off paging
	ld	(dpflag),a	;turn on future menu displays
	call	print
	db	'Command (<CR>=Menu',0
	ld	a,(cpmok)	;OK to return to CP/M?
	or	a		;0=No
	call	nz,prmptc
	ld	hl,(cstart)	;pt to first char
	ld	a,(hl)		;get it
	and	7FH		;mask
	cp	MFIRST
	call	nz,prmptf	;print previous menu prompt if not first menu
	ld	a,(nmenfl)	;next menu available?
	or	a		;0=No
	call	nz,prmptn		;print next menu prompt
	call	print
	db	') - ',0
	call	cin		;get response
	call	caps		;capitalize
	call	cout		;echo
	ld	b,a		;result in B

;
;  Check for CR
;
	cp	CR		;<CR>?
	jp	z,dispm2	;reprint menu if so

;
;  Check for Reboot
;
	ld	a,(cpmok)	;ok to abort?
	or	a		;0=No
	jp	z,prmpt0
	ld	a,b		;get command
	cp	CTRLC		;reboot?
	ret	z		;return to CP/M if so

;
;  Check for Command to Return to First Menu
;
prmpt0:
	ld	a,(hl)		;get it
	and	7FH		;mask
	cp	MFIRST
	jp	z,prmpt1
	ld	a,b		;get command
	cp	RFM		;return to first menu?
	jp	nz,prmpt1
	ld	hl,(mstart)	;pt to first menu
	xor	a		;A=0
	ld	(menuno),a
	jp	dmenu		;resume processing

;
;  Check for Command to go to Next Menu
;
prmpt1:
	ld	a,(nmenfl)	;next menu available?
	or	a		;0=No
	jp	z,prmpt2
	ld	a,b		;get command
	cp	RNMP		;goto next menu?
	jp	z,rnmx
	cp	RNM		;goto next menu?
	jp	nz,prmpt2
rnmx:
	ld	a,(menuno)	;increment menu number
	inc	a
	ld	(menuno),a
	ld	hl,(optstrt)	;pt to first option
nxtmnu:
	ld	a,(hl)		;get next char
	and	80H		;mask
	jp	nz,dmenu	;process next menu
	call	lskip		;goto beginning of next line
	jp	nxtmnu

;
;  Check for Command to go to Last Menu
;
prmpt2:
	ld	a,(hl)		;get menu char
	and	7FH		;at first menu?
	cp	MFIRST
	jp	z,prmpt3	;skip if at first menu
	ld	a,b		;get command
	cp	RLMP		;goto last menu?
	jp	z,lstmnu
	cp	RLM		;goto last menu?
	jp	nz,prmpt3
lstmnu:
	dec	hl		;back up
	ld	a,(hl)		;get char
	and	80H		;look for MSB
	jp	z,lstmnu
	ld	a,(menuno)	;decrement menu number
	dec	a
	ld	(menuno),a
	jp	dmenu		;process menu

;
;  Check for Command to goto System Menu
;
prmpt3:
	ld	a,(smenfl)	;system menu available?
	or	a		;0=No
	jp	z,prmpt4
	ld	a,b		;get command
	cp	RSM		;system menu?
	jp	nz,prmpt4
	call	password	;prompt for and get password
	jp	nz,prompt	;reprompt if error
	ld	hl,(smenadr)	;get address of system menu
	ld	a,(smeno)	;set system menu number
	ld	(menuno),a
	jp	dmenu		;process menu
;
;  This is where additional functions may be added
;
prmpt4:

;
;  Check for Option Letter
;
	ld	hl,(optstrt)	;pt to first option char
prmptx:
	ld	a,(hl)		;get it
	call	caps		;capitalize
	cp	MINDIC		;at next menu?
	jp	z,prmpter
	cp	b		;match user selection?
	jp	z,prmptd
	call	lskip		;skip to next line
	jp	prmptx

;
;  Invalid Option
;
prmpter:
	call	print
	db	cr,lf,'Invalid Option',cr,lf,0
	jp	prompt

;
;  Process Option
;
prmptd:
	xor	a		;set no wait
	ld	(wait),a
	inc	hl		;pt to first letter of command
	ld	a,(hl)		;get it
	cp	MCMD		;invoke other menu?
	jp	z,mchcmd	;menu change command
	cp	WOPTION		;turn on wait?
	jp	nz,prmptg
	ld	a,0FFH		;turn on wait
	ld	(wait),a
	inc	hl		;skip option char
prmptg:
	ex	de,hl		;DE pts to command letter
	ld	hl,(mcadr)	;get address of multiple command buffer
	ld	b,h		;... in BC also
	ld	c,l
	ld	a,4		;HL=HL+4 for address of first char
	add	a,l
	ld	l,a
	ld	a,h
	adc	a,0
	ld	h,a
	ld	a,l		;store address
	ld	(bc),a
	inc	bc
	ld	a,h
	ld	(bc),a
cmdcpy:
	ld	a,(de)		;get command letter
	call	caps		;capitalize it
	cp	cr		;done?
	jp	z,ccpyd
	cp	PCHAR		;prompt?
	jp	z,ccpyp
	ld	(hl),a		;store it
	inc	hl		;pt to next
	inc	de
	jp	cmdcpy
ccpyd:
	ld	(hl),CMDSEP	;store command separator
	inc	hl		;pt to next char
	ld	de,menucmd	;now store menu command to chain to when done
ccpd:
	ld	a,(de)		;get char
	or	a		;done?
	jp	z,ccpd1
	ld	(hl),a		;put char
	inc	hl		;pt to next
	inc	de
	jp	ccpd
ccpd1:
	ld	a,(wait)	;wait upon return?
	or	a		;0=No
	jp	z,ccpd2
	ld	(hl),WAITCH	;set letter in command line
	inc	hl		;pt to next char
ccpd2:
	ld	a,(menuno)	;get number of current menu
	ld	de,tnum		;buffer for number
	push	de		;save ptr
	call	madc		;store number
	pop	de
	ld	b,3		;3 chars max
ccpd3:
	ld	a,(de)		;get char
	inc	de		;pt to next
	cp	' '		;skip space
	jp	z,ccpd4
	ld	(hl),a		;put char
	inc	hl		;pt to next
ccpd4:
	DEC	B
	JP	NZ,CCPD3	;@@
;	djnz	ccpd3		;continue until all digits stored
	ld	(hl),0		;store ending zero
	jp	cmddisp		;optionally display command
;
;  Prompt User for Input and Accept It
;
ccpyp:
	inc	de		;pt to first char of prompt
	ex	de,hl		;HL pts to prompt char, DE pts to buffer
	call	crlf		;new line
	call	lprint		;print prompt
	ld	a,0ffh		;capitalize input from user
	ld	hl,ibuff	;input line buffer
	call	dots
	call	bline		;get input from user
	ex	de,hl		;HL pts to buffer, DE pts to user input
cmdlp:
	ld	a,(de)		;get char from user
	or	a		;end of input?
	jp	z,ccpyd		;store rest of line
	ld	(hl),a		;store char
	inc	hl		;pt to next
	inc	de
	jp	cmdlp

;
;  Check for Display of Loaded Command and Do So if Set
;
cmddisp:
	ld	a,(cpflag)	;display command?
	or	a		;0=No
	ret	z		;return to OS if so to run command
	call	crlf		;new line
	ld	hl,(mcadr)	;pt to first char
	ld	e,(hl)		;get low-order address
	inc	hl
	ld	d,(hl)		;get high-order address
	ex	de,hl		;HL pts to first char
cmdd1:
	ld	a,(hl)		;get char
	cp	CMDSEP		;done if command separator
	ret	z
	inc	hl		;pt to next
	call	cout		;print char
	jp	cmdd1

;
;  Menu Change Command -- Jump to Specified Menu
;
mchcmd:
	inc	hl		;pt to menu number
	call	eval		;convert to decimal number in A
;
;  Entry Point if MENU is Reinvoked
;
mchc0:
	ld	(menuno),a
	ld	b,a		;menu number in B
	xor	a		;turn off reentry flag
	ld	(reentry),a
	inc	b		;add 1 for initial offset
	ld	hl,(mstart)	;pt to first menu
mchc1:
	dec	b		;count down
	jp	z,dmenu		;found menu -- process it
mchc2:
	call	lskipt		;skip to next line
	jp	nz,mchc2	;continue if not end of menu display
mchc3:
	call	lskipt		;skip to next line
	jp	nz,mchc3	;continue if not at end of menu commands
	inc	hl		;end of MENU.CPR?
	ld	a,(hl)		;yes if double MINDIC
	and	7FH		;mask
	cp	MINDIC
	jp	z,mstrerr	;error if so
	dec	hl		;pt to first char
	jp	mchc1		;continue

;
;  Print Line pted to by HL Ending in <CR>
;    Decrement PAGCNT
;
lprintx:
	call	lprint		;print without <CR>
	jp	crlf		;do <CR> <LF>
;
;  Print Line Pted to by HL; Decrement PAGCNT
;
lprint:
	ld	b,0		;set tab counter
lprnt0:
	ld	a,(hl)		;get char
	inc	hl		;pt to next
	and	7FH		;mask MSB
	cp	TAB		;tabulate?
	jp	z,lprnt2
	cp	cr		;done?
	jp	z,lprnt1
	call	cout		;print
	inc	b		;incr tab counter
	jp	lprnt0
lprnt1:
	inc	hl		;pt to first char of next line
	ld	a,(pagcnt)	;count down pages
	dec	a
	ld	(pagcnt),a
	ret	nz
	ld	a,NLINES-1	;reset paging count
	ld	(pagcnt),a
	call	print
	db	cr,lf,'Pause -',0
	jp	sak
lprnt2:
	ld	a,' '		;print <SP>
	call	cout
	inc	b		;incr tab counter
	ld	a,b		;done?
	and	7		;every 8
	jp	nz,lprnt2
	jp	lprnt0

;
;  Strike Any Key Message
;
sak:
	call	print
	db	' Strike Any Key - ',0
	call	cin		;get response
	ret

;
;  Prompt for, input, and check password (only one chance)
;    If accepted, return with Zero Flag Set; if not, return with NZ
;
password:
	call	print
	db	cr,lf,'Pass? ',0
	ld	hl,ibuff	;pt to input line buffer
	call	dots
	xor	a		;don't capitalize user input
	call	bline		;get line from user
	ld	de,ppass	;pt to system password
pass1:
	ld	a,(de)		;get sys pass char
	cp	(hl)		;ok?
	jp	nz,passerr	;error if no match
	inc	hl		;pt to next
	inc	de
	or	a		;end of strings?
	jp	nz,pass1
	ret			;return with zero set to show match
passerr:
	call	print
	db	cr,lf,'Pass Err',0
	call	sak		;strike any key
	call	crlf
	ld	a,0FFH		;set no zero
	or	a
	ret

;
;  Skip to Beginning of Next Line and Test First Char for Menu Indicator
;
lskipt:
	call	lskip		;skip
	ld	a,(hl)		;get char
	and	7FH		;mask
	cp	MINDIC		;test
	ret

;
;  Skip to Beginning of Next Line
;
lskip:
	ld	a,(hl)		;get char
	and	7FH		;mask out MSB
	inc	hl		;pt to next
	cp	lf
	jp	nz,lskip
	ret

;
;  Print CP/M Return Prompt
;
prmptc:
	call	print
	db	', ^C=ZCPR2',0
	ret
;
;  Print First/Last Menu Chars
;
prmptf:
	call	print
	db	', ',RFM,'=1st Menu, ',RLM,'=Prev Menu',0
	ret
;
;  Print next menu message
;
prmptn:
	call	print
	db	', ',RNM,'=Next Menu',0
	ret

;
;  Menu Structure Error -- FATAL
;    This message is printed to indicate an error in the structure of
; the MENU.CPR file.
;
mstrerr:
	call	print
	db	'Str Err',0
	ret

;
;  Convert char string pted to by HL into decimal number in A
;	On Entry, HL pts to first digit char
;	On Exit, HL pts to after last digit char and A=number
;
eval:
	push	bc		;save BC
	ld	b,0		;set value
eval1:
	ld	a,(hl)		;get digit
	sub	'0'		;convert to binary
	jp	c,eval2
	cp	10		;range?
	jp	nc,eval2
	inc	hl		;pt to next digit
	ld	c,a		;new digit in C
	ld	a,b		;multiply B by 10
	add	a,a		;*2
	add	a,a		;*4
	add	a,b		;*5
	add	a,a		;*10
	add	a,c		;add in new digit
	ld	b,a		;result in B
	jp	eval1
eval2:
	ld	a,b		;result in A
	pop	bc		;restore ptr
	ret

;
;  Print Dots to Indicate Buffer Size
;
dots:
	push	bc		;save BC
	ld	a,(ibuff)	;get count
	ld	b,a		;... in B
	ld	c,a		;... in C
	ld	a,'.'		;dot
dots1:
	call	cout		;print dot
	DEC	B		;@@
	JP	NZ,DOTS1
;	djnz	dots1
	ld	a,8		;back space
	ld	b,c		;count in B
dots2:
	call	cout		;print back space
	DEC	B
	JP	NZ,DOTS2	;@@
;	djnz	dots2
	pop	bc		;restore BC
	ret

;
;  Buffers
;
menucmd:
	db	'MENU ',0	;MENU command line
;
;  These buffers overlay the scratch area to save space
;
wait	equ	scratch		;Wait Upon Return Flag
optstrt	equ	wait+1		;Address of First Option in Current Menu
mstart	equ	optstrt+2	;Address of First Menu
cstart	equ	mstart+2	;Address of Current Menu
smenfl	equ	cstart+2	;System Menu Available Flag (0=No)
smeno	equ	smenfl+1	;System Menu Number
smenadr	equ	smeno+1		;Address of First Byte of System Menu
nmenfl	equ	smenadr+2	;Next Menu Available Flag (0=No)
mladr	equ	nmenfl+1	;Menu Load Address (1st byte of menu in memory)
menuno	equ	mladr+2		;Number of Menu
pagcnt	equ	menuno+1	;Paging Counter
cflag	equ	pagcnt+1	;Display Command Line Flag
dflag	equ	cflag+1		;Display Menu Flag
pflag	equ	dflag+1		;Paging Flag
cpflag:
	ds	1		;Temp Display Command Line Flag
dpflag:
	ds	1		;Temp Display Menu Flag
ppflag:
	ds	1		;Temp Paging Flag
reentry:
	ds	1		;Menu Reentry Flag and Number
cpmok:
	ds	1		;OK to Return to CP/M (0=No)
ibuff:
	db	40		;40 chars in buffer
	db	0		;buffer char count
tnum:
	ds	41		;space for chars and ending 0

	end
